/**
 * 数据转换工具函数模块
 * @module utils/convert
 */

/**
 * 对象数组的去重函数  依照某个 id去重
 * @param {Object[]} list 对象数组
 * @param {string} [idKey=id] id字段名称
 */
export function duplicateArr(list = [], idKey = 'id') {
	const obj = {},
		Arr = [];
	list.forEach((item) => {
		if (!obj[item[idKey]]) {
			Arr.push(item);
			obj[item[idKey]] = item;
		}
	});
	return Arr;
}

/**
 * 深度拷贝对象或数组，采用JSON.parse 和 JSON.stringify 实现, 相同功能的方法 [cloneDeep]{@link module:utils/convert.cloneDeep}
 * @param {Object|Array} obj 要拷贝的对象或数组
 * @returns {Object|Array} 拷贝后的对象副本
 */
export function clone(obj) {
	return JSON.parse(JSON.stringify(obj));
}

/**
 * 检测数据类型
 * @param {*} obj 需要检测的数据
 * @returns {string} boolean / number / string / function / array / date / regExp / undefined / null / object
 */
export function typeOf(obj) {
	const toString = Object.prototype.toString;
	const map = {
		'[object Boolean]': 'boolean',
		'[object Number]': 'number',
		'[object String]': 'string',
		'[object Function]': 'function',
		'[object Array]': 'array',
		'[object Date]': 'date',
		'[object RegExp]': 'regExp',
		'[object Undefined]': 'undefined',
		'[object Null]': 'null',
		'[object Object]': 'object',
		'[object Promise]': 'Promise'
	};
	return map[toString.call(obj)];
}

/**
 * 深度拷贝对象或数据
 * @param {*} data 需要拷贝的数据
 * @returns {*} 拷贝后的数据副本 WeakMap作为记录对象Hash表（用于防止循环引用）
 * @see [cloneDeep]{@link utils/convert.cloneDeep}
 */
export function cloneDeep(obj, visited = new WeakMap()) {
	// 基本类型直接返回
	if (typeof obj !== 'object' || obj === null) return obj;

	// 如果该对象已存在，则直接返回该对象
	if (visited.has(obj)) return visited.get(obj);

	// 数组类型
	if (Array.isArray(obj)) {
		const copy = [];
		visited.set(obj, copy);
		for (const i in obj) {
			copy[i] = cloneDeep(obj[i], visited);
		}
		return copy;
	}

	//日期
	if (obj instanceof Date) return new Date(obj);

	//正则对象
	if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);

	// 处理Map对象
	if (obj instanceof Map) {
		const copy = new Map();
		visited.set(obj, copy);
		obj.forEach((value, key) => {
			copy.set(cloneDeep(key, visited), cloneDeep(value, visited));
		});
		return copy;
	}

	// 处理Set对象
	if (obj instanceof Set) {
		const copy = new Set();
		visited.set(obj, copy);
		obj.forEach((value) => {
			copy.add(cloneDeep(value, visited));
		});
		return copy;
	}

	// 对象
	const copy = {};
	visited.set(obj, copy);
	for (const key in obj) {
		// hasOwnProperty表示是否有自己的属性。这个方法会查找一个对象是否有某个属性，但是不会去查找它的原型链。
		if (Object.prototype.hasOwnProperty.call(obj, key)) {
			copy[key] = cloneDeep(obj[key], visited);
		}
	}
	return copy;
}
